#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <termios.h>
#include <pty.h>
#include <string.h>
#include <utmp.h>
#include <sys/signal.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/stropts.h> 

#include "base64.h"

#define SHELL "/bin/bash"
#define MSNGR2SERVER "/tmp/m2s"
#define SERVER2MSNGR "/tmp/s2m"
#define BUFFER_LENGTH 200
#define DATA_LENGTH 100

int ret_fd,fd_m2s,fd_s2m;
struct termios tp1;
struct termios tp2;

void 
writef() {
  int i = 0, max_fd, flag = 0, read_result;
  char the_buff[150];
  char *temp;
  fd_set read_fds;
  fd_set write_fds;
  int select_result, val;
  struct timeval timeout;
    
  do {	
    if ((read_result = read (fd_m2s, the_buff, DATA_LENGTH)) > 0) {
      if (strstr (the_buff, "newl") != NULL) {
	the_buff[0] = '\r';   
      }
      while (flag == 0) {
	FD_ZERO (&read_fds);
	FD_ZERO (&write_fds);
	FD_SET (ret_fd, &write_fds);
	timeout.tv_sec = 1;
	timeout.tv_usec = 0;
	max_fd = ret_fd;
	      
	select_result = select (max_fd + 1, &read_fds, &write_fds,
				NULL, &timeout);
	if (select_result > 0) {
	  if ((val = FD_ISSET (ret_fd, &read_fds))) {
	    continue;
	  }
	  else if ((val = FD_ISSET (ret_fd, &write_fds)) != 0) {
	    temp = &the_buff[i++];
	    write (ret_fd, temp, 1);
	    flag = 1;
	    break;
	  }	
	}
      }
      if (flag == 1)
	break;
    }
    else 
      perror("\nRead error for m2s:");
  } while (1);	
}


void 
readf() {
  int max_fd, cnt = 0, i;
  unsigned char the_buffer, sending[DATA_LENGTH], data[BUFFER_LENGTH];
  char target[BUFFER_LENGTH];
  fd_set read_fds2;
  fd_set write_fds2;
  int select_result;
  ssize_t read_result;
  struct timeval timeout;
  size_t sourcelen = DATA_LENGTH, targetlen = BUFFER_LENGTH;

  data[0] = 'p';
  data[1] = 'r';
  data[2] = 'd';
  data[3] = 's';
  data[4] = 's';
  data[5] = 'h';
  data[6] = ':';	

  do {
    FD_ZERO (&write_fds2);
    FD_ZERO (&read_fds2);
    FD_SET (ret_fd,&read_fds2);
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    max_fd = ret_fd;
    select_result = select (max_fd + 1, &read_fds2, &write_fds2,
			    NULL, &timeout);
    if (select_result > 0) {
      if (FD_ISSET (ret_fd, &write_fds2))
	continue;
      else
	if (FD_ISSET (ret_fd, &read_fds2)) {
	  read_result = read (ret_fd, &the_buffer, 1);
	  if (read_result < 0)
	    perror ("\nError ");
	  else { 
	    sending[cnt++] = the_buffer;
	    if (cnt == DATA_LENGTH) {
	      base64_encode (sending, sourcelen, target, targetlen);
	      for (i = 0 ; i < 193 ; i++)
		data[i + 7] = target[i];
	      write (fd_s2m, data, BUFFER_LENGTH);
	      cnt = 0;
	    }
	  }
	}
	else
	  break;
    }
    else
      break;
  } while (1);
  sending[cnt] = '\0';
  base64_encode (sending, sourcelen, target, targetlen);
  for (i = 0 ; i < 193 ; i++) {
    data[i + 7] = target[i];
  }
  write (fd_s2m, data, BUFFER_LENGTH);
}

int 
main() {
  int status, flag = 1;
  int saved_stderr;
  pid_t pid,pid2;
  struct winsize window_size;

  unlink ("MSNGR2SERVER");
  if (mkfifo ("MSNGR2SERVER", 010777) == -1)
    perror ("\nError in mkfifo : ");
  else if ((fd_s2m = open ("SERVER2MSNGR",O_WRONLY)) == -1)
    printf ("\nerror in opening fifo\n");
  ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size);
  pid = forkpty (&ret_fd, NULL, NULL, &window_size);
  if (pid == 0) {
    if (execl (SHELL, "bash", NULL) < 0)
      printf ("\nError in execl\n");
    exit (0);
  } 
  else if (pid < 0) {
    perror ("2. ERROR spawning programme");
    return -1;
  }
  else {  // if pid > 1
    do {	
      readf ();
      if (flag == 1) {
	if ((fd_m2s = open ("MSNGR2SERVER", O_RDONLY|O_NONBLOCK)) == -1)
	  printf ("\nerror in opening fifo\n");
	else
	  printf ("\nPipe m2s opened successfully\n");
	flag = 0;
      }
      writef ();
    } while (1);
    pid2 = wait (&status);
    printf ("\nstatus : %d\n", status);
    close (saved_stderr);
  }
  return 0;
}
